package com.wcgksoft.common.filter.shiro;


import com.wcgksoft.common.util.exception.CaptchaException;
import com.wcgksoft.config.shiro.ShiroConstants;
import com.wcgksoft.entity.admin.Account;
import com.wcgksoft.entity.system.SysMenu;
import com.wcgksoft.entity.system.SysUser;
import com.wcgksoft.service.JurisService;
import com.wcgksoft.service.admin.AccountService;
import com.wcgksoft.service.system.UserService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 自定义认证、授权
 *
 * @author Thinkpad 参考：yunnex.saofu.web.service.shiro.AuthShiroRealm
 */
@Service
public class UserAuthorizingRealm extends AuthorizingRealm {
  private static Logger logger = LoggerFactory.getLogger(UserAuthorizingRealm.class);

  @Resource
  private UserService userService;

  @Resource

  private AccountService accountService;

  @Resource
  private JurisService jurisService;


  private static final String USER_SESSION_KEY = "om_user";

  /**
   * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
   * 比如遇到@RequiresPermissions注解时，会调用
   */
  @Override
  protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    logger.info("授权查询回调函数");

    // 获取登录时输入的用户名
    String username = (String) principals.getPrimaryPrincipal();

    Session session = SecurityUtils.getSubject().getSession();
    Account omSysUser = (Account) session.getAttribute(USER_SESSION_KEY);

    // 权限信息对象，用来存放查出的用户的所有的角色（role）及权限（permission）等
    SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
    if (null != omSysUser) {
      authorizationInfo.setRoles(this.getUserRoles(omSysUser.getId()));
      authorizationInfo.setStringPermissions(this.getUserPermissions(omSysUser.getId()));
    }

    return authorizationInfo;
  }

  /**
   * 认证回调函数,登录时调用
   */
  @Override
  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    logger.info("认证回调函数");

		/*
		在自定义的认证过滤器中将验证码保存至KaptchaCodeToken中
		 此处的Token就是认证过滤器中实例化的Token,可以直接强制转换
		 */
    CaptchaToken captchaToken = (CaptchaToken) token;
		/*
		获取用户在登录页面输入的验证码
		 */

    String loginCaptcha = captchaToken.getCaptchaCode();
		/*
			抛出自定义异常(继承AuthenticationException), Shiro会捕获AuthenticationException异常
			发现该异常时认为登录失败,执行登录失败逻辑,登录失败页中可以判断如果是CaptchaEmptyException时为验证码为空
		*/
    if (loginCaptcha == null || "".equals(loginCaptcha)) {

      throw new CaptchaException("请输入验证码！");
    }

      	/*
         获取SESSION中的验证码
         Kaptcha在生成验证码时会将验证码放入SESSION中
         默认KEY为KAPTCHA_SESSION_KEY, 可以在Web.xml中配置
        */
    String sessionCaptcha = (String) SecurityUtils.getSubject().getSession().getAttribute(ShiroConstants.CURRENT_CAPTCHA);

    if (!loginCaptcha.equals(sessionCaptcha)) {
      throw new CaptchaException("验证码输入错误！");
    }

    UsernamePasswordToken authcToken = (UsernamePasswordToken) token;
    Account omSysUser = null;
    try {

      DetachedCriteria criteria = DetachedCriteria.forClass(Account.class);
      criteria.add(Restrictions.eq("userName", authcToken.getUsername()));
      List<Account> list = accountService.findByConditions(criteria);
      if (list.size() > 0) {
        omSysUser = list.get(0);
      }
    } catch (Exception e) {
      logger.error("身份认证发生异常", e);
      throw new AuthenticationException("身份认证发生异常");
    }

    if (null == omSysUser) {
      logger.warn("身份认证失败，登录名不存在");
      throw new UnknownAccountException("身份认证失败，登录名不存在");
    }

    if (1 != omSysUser.getStatus()) {
      logger.warn("身份认证失败，用户已被禁用");
      throw new LockedAccountException("身份认证失败，用户已被禁用");
    }

    // 密码验证
    if (!omSysUser.getPassWord().equals(String.valueOf(authcToken.getPassword()))) {
      logger.warn("身份认证失败，登录密码不正确");
      throw new IncorrectCredentialsException("身份认证失败，登录密码不正确");
    }
    //SecurityUtils.getSubject().getSession().setTimeout(60000);
    Session session = SecurityUtils.getSubject().getSession();
    session.setAttribute(USER_SESSION_KEY, omSysUser);

    return new SimpleAuthenticationInfo(authcToken.getUsername(), authcToken.getPassword(), getName());
  }

  ///////////////////////////////////////// private////////////////////////////////////

  /**
   * 获取用户角色
   *
   * @param userId
   * @return
   */
  private Set<String> getUserRoles(Integer userId) {
    Account sysUser = accountService.findById(userId);
       /* DetachedCriteria criteria = DetachedCriteria.forClass(SysRole.class);
        criteria.add(Restrictions.eq("userid", userId));
        List<SysRole> orSysRoleList = jurisService.findByConditions(criteria);*/
    Set<String> roles = new HashSet<>();
    if (null != sysUser.getAuthority()) {
      roles.add(sysUser.getAuthority().getRoleCode());
    }

    /*    if (CollectionUtils.isEmpty(orSysRoleList)) {
            return roles;
        }

        for (SysRole or : orSysRoleList) {
            roles.add(or.getSysRoleCode().getRole_number());
        }*/

    return roles;
  }

  /**
   * 获取用户权限
   *
   * @param userId
   * @return
   */
  private Set<String> getUserPermissions(Integer userId) {

    Account user = accountService.findById(userId);
   /* DetachedCriteria criteria = DetachedCriteria.forClass(SysRole.class);
    criteria.add(Restrictions.eq("userid", userId));
    List<SysRole> permisList = jurisService.findByConditions(criteria);
*/

    //List<OmPermis> permisList = omPermisService.findByConditions(criteria);
    Set<String> stringPermissions = new HashSet<>();
    if (null==user.getAuthority()){
      return stringPermissions;
    }else{
      return stringPermissions;
    }
   /* if (CollectionUtils.isEmpty(user.getAuthority())) {
      return stringPermissions;
    }*/
/*
    for (SysRole op : permisList) {
      for (SysMenu menu : op.getSysMenuSet()) {
        stringPermissions.add(menu.getAuthority());
      }
    }*/

/*
    for (SysMenu menu : user.getSysRole().getSysMenuSet()) {
      stringPermissions.add(menu.getAuthority());
    }
*/
  }

}
